package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;

/**
 * @author 虎哥
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    private final BrandService brandService;
    private final CategoryService categoryService;
    private final SpuDetailService detailService;
    private final SkuService skuService;
    private final SpecParamService paramService;
    private final AmqpTemplate amqpTemplate;

    public SpuServiceImpl(BrandService brandService, CategoryService categoryService, SpuDetailService detailService, SkuService skuService, SpecParamService paramService, AmqpTemplate amqpTemplate) {
        this.brandService = brandService;
        this.categoryService = categoryService;
        this.detailService = detailService;
        this.skuService = skuService;
        this.paramService = paramService;
        this.amqpTemplate = amqpTemplate;
    }

    @Override
    public PageDTO<SpuDTO> querySpuByPage(Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        // 健壮性判断
       int current = Math.max(page, 1);
       int size = Math.max(rows, 5);

        // 分页查询
        // select * from tb_spu
        Page<Spu> result = query()
                // where saleable = true
                .eq(saleable != null, "saleable", saleable)
                // AND cid3 = 14124
                .eq(categoryId != null, "cid3", categoryId)
                // AND brand_id = 141532
                .eq(brandId != null, "brand_id", brandId)
                // AND id = 123
                .eq(id != null, "id", id).
                // limit 0, 5
                        page(new Page<>(current, size));

        // 解析result
        long total = result.getTotal();
        long totalPage = result.getPages();
        List<Spu> list = result.getRecords();
        List<SpuDTO> dtoList = SpuDTO.convertEntityList(list);

        // 设置品牌和分类的名称
        for (SpuDTO spuDTO : dtoList) {
            handleCategoryAndBrandName(spuDTO);
        }

        // 封装返回
        return new PageDTO<>(total, totalPage, dtoList);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        // 1.新增spu
        // 1.1.dto转换po
        Spu spu = spuDTO.toEntity(Spu.class);
        // 1.2.设置默认值
        spu.setSaleable(false);
        // 1.3.写入数据库
        save(spu);
        // 1.4.获取id
        Long spuId = spu.getId();

        // 2.新增spuDetail
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        // 2.1.转换
        SpuDetail detail = spuDetailDTO.toEntity(SpuDetail.class);
        // 2.2.填写id
        detail.setSpuId(spuId);
        // 2.3.写入数据库
        detailService.save(detail);

        // 3.新增Sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        List<Sku> skuList = new ArrayList<>(skuDTOList.size());
        // 3.1.循环
        for (SkuDTO skuDTO : skuDTOList) {
            // 3.2.转换DTO
            Sku sku = skuDTO.toEntity(Sku.class);
            // 3.3.填默认值
            sku.setSpuId(spuId);
            sku.setSaleable(false);
            skuList.add(sku);
        }
        // 3.4.批量写入数据库
        skuService.saveBatch(skuList);
    }

    @Override
    @Transactional
    public void updateSaleable(Long id, Boolean saleable) {
        // 根据id修改SPU的上下架 update tb_spu set saleable = #{saleable} where id = #{id}
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        updateById(spu);
        // 修改sku的上下架 update tb_sku set saleable = #{saleable} where spu_id = #{id}
        skuService.update().set("saleable", saleable).eq("spu_id", id).update();

        // 发送MQ消息，通知其它服务
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, routingKey, id);
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        // 1.查询spu
        Spu spu = getById(id);
        SpuDTO spuDTO = new SpuDTO(spu);

        // 2.查询spuDetail
        SpuDetail detail = detailService.getById(id);
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));

        // 3.查询sku
        List<Sku> list = skuService.query().eq("spu_id", id).list();
        spuDTO.setSkus(SkuDTO.convertEntityList(list));

        // 4.分类和品牌名称
        handleCategoryAndBrandName(spuDTO);
        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        Long spuId = spuDTO.getId();
        // 1.判断spu的id是否为null
        if (spuId != null) {
            //	否：需要修改spu
            Spu spu = spuDTO.toEntity(Spu.class);
            // 不允许修改saleable字段
            spu.setSaleable(null);
            boolean success = updateById(spu);
            if (!success) {
                throw new LyException(500, "更新spu失败！");
            }
        }

        // 2.判断spuDetail是否为null
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        if(detailDTO != null && detailDTO.getSpuId() != null){
            // 否：需要修改
            SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
            boolean success = detailService.updateById(detail);
            if (!success) {
                throw new LyException(500, "更新spuDetail失败！");
            }
        }

        // 3.判断skus是否为空
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        if(CollectionUtils.isEmpty(skuDTOList)){
            // 是：无需修改
            return;
        }
        /*List<Sku> saveOrUpdateSkuList = new ArrayList<>();
        List<Sku> deleteSkuList = new ArrayList<>();
        for (SkuDTO skuDTO : skuDTOList) {
            Sku sku = skuDTO.toEntity(Sku.class);
            if (sku.getSaleable() != null) {
                deleteSkuList.add(sku);
            }else{
                saveOrUpdateSkuList.add(sku);
            }
        }*/
        // 否：需要修改
        Map<Boolean, List<Sku>> skuMap = skuDTOList.stream()
                // 转换SkuDTO为sku
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                // 判断是否包含saleable，并且以判断结果为key分组，存储map中
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));
        // 如果包含saleable，就是删除操作
        List<Sku> deleteSkuList = skuMap.get(true);
        if(!CollectionUtils.isEmpty(deleteSkuList)) {
            // 如果有要删除的
            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            skuService.removeByIds(idList);
        }

        // 如果不包含saleable：就是增或改操作
        List<Sku> saveOrUpdateSkuList = skuMap.get(false);
        if(!CollectionUtils.isEmpty(saveOrUpdateSkuList)) {
            // 如果有，就执行增或改
            skuService.saveOrUpdateBatch(saveOrUpdateSkuList);
        }
    }

    @Override
    public List<SpecParamDTO> querySpecValues(Long spuId, Boolean searching) {
        // 1.查询tb_spu_detail表，得到的是SpuDetail中的specification，规格参数值
        SpuDetail detail = detailService.getById(spuId);
        // 1.1.获取规格参数json
        String json = detail.getSpecification();
        // 1.2.转为一个Map
        Map<Long, Object> specification = JsonUtils.toMap(json, Long.class, Object.class);

        // 2.查询tb_spec_param表，得到的是SpecParam
        // 2.1.查询商品Spu
        Spu spu = getById(spuId);
        // 2.2.查询规格参数
        Long categoryId = spu.getCid3();
        List<SpecParamDTO> list = paramService.querySpecParams(categoryId, null, searching);
        // 2.3.给param填value
        for (SpecParamDTO paramDTO : list) {
            paramDTO.setValue(specification.get(paramDTO.getId()));
        }
        return list;
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        // 根据分类id查询分类名称
        List<Long> categoryIds = spuDTO.getCategoryIds();
        String names = categoryService.listByIds(categoryIds)
                .stream()
                .map(Category::getName)
                .collect(Collectors.joining("/"));
        spuDTO.setCategoryName(names);
        // 根据品牌id查询品牌名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if (brand != null) {
            spuDTO.setBrandName(brand.getName());
        }
    }
}
